﻿using DocumentFormat.OpenXml.Lite.Core.Relationship;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using IO = System.IO;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Lite.Core.DocumentFS;

namespace DocumentFormat.OpenXml.Lite.Core.Office
{
    public enum DocumentType
    {
        Word,
        Excel,
        Presentation
    }

    public class DocumentManager
    {
        #region Singleton

        private static DocumentManager instance;
        public static DocumentManager Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new DocumentManager();
                }
                return instance;
            }
        }

        #endregion

        private Dictionary<Guid, DocumentBase> documents;

        private DocumentManager()
        {
            documents = new Dictionary<Guid, DocumentBase>();
        }

        public void AddDocument(Guid id, DocumentBase doc)
        {
            documents.Add(id, doc);
        }

        public DocumentBase FindDocument(Guid id)
        {
            if (documents.ContainsKey(id))
                return documents[id];
            return null;
        }

        public bool SaveDocument(Guid id, string path)
        {
            if (IO.Path.GetDirectoryName(path) != string.Empty &&
                !IO.Directory.Exists(IO.Path.GetDirectoryName(path)))
            {
                IO.Directory.CreateDirectory(IO.Path.GetDirectoryName(path));
            }

            if (IO.File.Exists(path))
            {
                IO.File.Delete(path);
            }

            using (IO.FileStream fs = IO.File.Create(path))
            {
                return SaveDocument(id, fs);
            }
        }

        public bool SaveDocument(Guid id, IO.Stream stream)
        {
            ZipOutputStream zipStream = new ZipOutputStream(stream);

            Directory sandbox = DocumentFS.DocumentFS.GetSandbox(id);
            SaveFiles(sandbox, zipStream);

            zipStream.IsStreamOwner = false;
            zipStream.Close();

            DisposeDocument(id);

            return true;
        }

        private void SaveFiles(Directory directory, ZipOutputStream zipStream)
        {
            foreach (var file in directory.GetFiles())
            {
                CreateZipEntry(file.Object.Serialize(), file, zipStream);
            }

            foreach (var dir in directory.GetDirectories())
            {
                SaveFiles(dir, zipStream);
            }
        }
        
        public bool OpenDocument(IO.Stream fs, DocumentBase docBase)
        {
            ZipFile zipFile = new ZipFile(fs);

            bool ret = true;
            try
            {
                foreach (ZipEntry entry in zipFile)
                {
                    docBase.ExtractFile(entry.Name, zipFile.GetInputStream(entry));
                }
            }
            catch
            {
                ret = false;
            }
            finally
            {
                zipFile.IsStreamOwner = true;
                zipFile.Close();
            }

            return ret;
        }

        private void CreateZipEntry(byte[] source, File file, ZipOutputStream zipStream)
        {
            IO.MemoryStream xml = new IO.MemoryStream(source);
            ZipEntry entry = new ZipEntry(file.GetXmlPath().Replace('/', '\\'));
            entry.DateTime = DateTime.Now;
            zipStream.PutNextEntry(entry);
            StreamUtils.Copy(xml, zipStream, new byte[4096]);
            zipStream.CloseEntry();
        }

        private bool DisposeDocument(Guid id)
        {
            bool success = true;
            success &= documents.Remove(id);
            success &= DocumentFS.DocumentFS.Root.RemoveDirectory(id.ToString());
            return success;
        }
    }
}
